查看原文
其他

画线纹理的一种简单实现!

lamyoung 白玉无冰 2022-06-10

cc.Graphics 画线也能加纹理了?文末附送完整代码。

初探精灵中的网格渲染模式 ! 中简单分析了 Sprite 组件的渲染模式 Mesh

这次,我们应用 Sprite 渲染模式 Meshcc.Graphics ,实现画线纹理的操作。

先看看效果如何。

先在场景创建一个 cc.Graphics 节点,并添加一个子节点 cc.Sprite ,渲染模式改为 Mesh

因为 Mesh 中的原点坐标是左上角,而 Graphics 画图是从中心开始画的。

所以 cc.Sprite 节点, Scale 调整为 (1,-1)Anchor 调整为 (0,1)

为了使纹理超出边界后可以重复填充,这个纹理大小得是 2n 次方,并设为 Repeat

画纹理肯定需要坐标位置信息。

来一起看看,Graphicswebgl 实现。

Graphics 中有一个 _impl 变量。

这个 _impl 里有一个 _paths 变量,记录了所有画线路径和对应的画线的点。

而 lineTomoveTo都会往 _paths 塞入画线的点数据。

对于 circlearc 以及 rect 等接口,最终还是调用 lineTomoveTo

所以有了这个 _paths 我们画纹理的时候,可以先把点遍历出来。

for (let index = 0; index < _impl._paths.length; index++) { const path = _impl._paths[index]; const pathPoints = path.points; if (pathPoints.length < 2) continue; for (let index2 = 1; index2 < pathPoints.length; index2++) { // 当前点 const p = cc.v2(pathPoints[index2].x, pathPoints[index2].y); // 上一个点 const p_pre = cc.v2(pathPoints[index2 - 1].x, pathPoints[index2 - 1].y); }}

如何画纹理呢?

先考虑相邻的两个点,再根据线宽 w 画一个长方形。长方形有四个点,我们要求出这四个点的坐标。

先算出这两个点的方向。

const dir = p.sub(p_pre); //方向

接着求出一个垂直方向的向量(根据向量内积为0求出),长度为线宽一半。

const cross_dir = (dir.y == 0 ? cc.v2(0, 1) : cc.v2(1, -dir.x / dir.y).normalize()).mulSelf(w / 2); //垂直方向

根据两个点和垂直方向可以求出这个长方形的四个顶点。

const p_r_t = p.add(cross_dir); //右上const p_r_b = p.sub(cross_dir); // 右下const p_l_t = p_pre.add(cross_dir); // 左上const p_l_b = p_pre.sub(cross_dir); // 左下

最后根据四个点填充 sprite.spriteFrame 中的数据 vertices ,如果不理解的话,可以参考初探精灵中的网格渲染模式 !

对于 uv 纹理坐标,这边就直接使用缩放一个系数的顶点坐标。参考代码如下。

const uv_mul = 50;const i_offset = vertices.x.length;vertices.x.push(p_r_t.x, p_r_b.x, p_l_t.x, p_l_b.x);vertices.y.push(p_r_t.y, p_r_b.y, p_l_t.y, p_l_b.y);vertices.nu.push(p_r_t.x / uv_mul, p_r_b.x / uv_mul, p_l_t.x / uv_mul, p_l_b.x / uv_mul);vertices.nv.push(p_r_t.y / uv_mul, p_r_b.y / uv_mul, p_l_t.y / uv_mul, p_l_b.y / uv_mul);
vertices.triangles.push(i_offset + 0);vertices.triangles.push(i_offset + 1);vertices.triangles.push(i_offset + 2);vertices.triangles.push(i_offset + 1);vertices.triangles.push(i_offset + 2);vertices.triangles.push(i_offset + 3);

这么画长方形存在一个问题,对于画圆弧,如果分隔太大,或者线宽比较大,会出现分割的问题。

怎么解决这个问题呢?

一是可以参考源码,把连接处补上。

另一种方式是直接用 GraphicsAssembler 中的 buffers 数据,重新组织一下。

当然,这些等我研究出来再分享给大家(日常挖坑),点个关注,点个在看不迷路!

以上为白玉无冰使用 Cocos Creator v2.3.3 关于 "画线纹理的一种简单实现!"的技术分享。如果对你有点帮助,欢迎分享给身边的朋友。



讲一讲这个公众号吧!2019年第一季度原创精选整理!

初探精灵中的网格渲染模式 !

物理挖洞之 3D 效果!

物理流体的一种实现

使用 mesh 实现多边形裁剪图片!

飘扬的旗帜!shader 编程实战!

转载请保留文末二维码和完整代码获取方式!

完整代码: 

https://github.com/baiyuwubing/cocos-creator-examples/tree/master/graphics_sprite

点击“阅读原文”查看精选导航

“在看”是最大的鼓励▼

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存